/*
    wnd.c

  14:47:39 17-09-2015

    Generated by VISG v.0.952

    VISG: visual and smart GUI builder
    Get the latest version of VISG at
    http://codege.org/
    http://mrhx.ucoz.com/

    Tested on Visual C++ 6.0 and devcpp
*/

#include <windows.h>
#include <commctrl.h>        // INCLUDE LIBRARY comctl32.lib INTO YOUR PROJECT!
//#include "resource.h"   // UNCOMMENT THIS IF YOU USE RESOURCES.
#include <windowsx.h>
#include <stdio.h>
#include <stdarg.h>
#include "version.h"
#include <stdlib.h>
#include <direct.h>
#include "nargv.h"
#include "shlwapi.h"
#include <richedit.h>
#include "swnd.h"
#include "recent.h"
#include "shlobj.h"
#include "config.h"
#include "search.h"
#include "save.h"
#include "shlink.h"
#include <tchar.h>

void text_append (const char *fmt, ...);
void text_set    (const char *txt);
void text_read_only (int ro);

static void resize_controls (void);

// names of window classes.
#define WND_CLASS_NAME0 "my_wnd_class_name_0"

// function prototypes.
void register_classes();
int message_loop();
HWND create_wnd0();
void create_wnd_content0(HWND parent);
LRESULT CALLBACK wnd_proc0(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
void on_results_click (int item);

// global data.
HINSTANCE instance;
HFONT h_font;

// global data added.
HFONT h_font_code;
LOGFONT clfnt;

HWND  hMainWindow;
HWND  hStatus;
HWND  hDlgCurrent = NULL;
HWND  hResult;
HWND  hRTF;
HWND  hLN;

int OnActivateEscape = 0;

int ClickedItem;

LONG LNWidth = 0;

char MyPath[_MAX_PATH];
char ConfigPath[_MAX_PATH];
char CurrentPath[_MAX_PATH];
static char SendtoPath[_MAX_PATH];

void populate_dir (void);

/******************************************************************************/
static void do_gui_main_action (LPSTR cmdline)
{
  NARGV *args = nargv_parse(cmdline);

  if (args->argc > 0)  {
    if (DirectoryExists(args->argv[0]))  {
      SetWindowText(GetDlgItem(hMainWindow, IDC_MANPATH), args->argv[0]);
      DoEvents (NULL);
      populate_dir ();
    }
  }
  nargv_free (args);
}

/******************************************************************************/
void get_options (void)
{
  OptRegex = (IsDlgButtonChecked(hMainWindow, IDC_RE) == BST_CHECKED) ? 1 : 0;
  OptCasesense = (IsDlgButtonChecked(hMainWindow, IDC_CASE) == BST_CHECKED) ? 1 : 0;
  OptUtf = ComboBox_GetCurSel (GetDlgItem(hMainWindow, IDC_ENCODING));
  OptSaveEncoding = ComboBox_GetCurSel (GetDlgItem(hMainWindow, IDC_SENCODING));
  OptRecursive = (IsDlgButtonChecked(hMainWindow, IDC_RECURSIV) == BST_CHECKED) ? 1 : 0;
  GetWindowText(GetDlgItem(hMainWindow, IDC_MASK), FileMask, sizeof(FileMask));
  config_save ();
}
/******************************************************************************/
static void set_options (void)
{
  ComboBox_SetCurSel (GetDlgItem(hMainWindow, IDC_ENCODING), OptUtf);
  ComboBox_SetCurSel (GetDlgItem(hMainWindow, IDC_SENCODING), OptSaveEncoding);
  Edit_SetText (GetDlgItem(hMainWindow, IDC_MASK), FileMask);
  CheckDlgButton (hMainWindow, IDC_RE, OptRegex ? BST_CHECKED : BST_UNCHECKED);
  CheckDlgButton (hMainWindow, IDC_CASE, OptCasesense ? BST_CHECKED : BST_UNCHECKED);
  CheckDlgButton (hMainWindow, IDC_RECURSIV, OptRecursive ? BST_CHECKED : BST_UNCHECKED);
}

/******************************************************************************/
static void current_path_to_edit (void)
{
int cur;
HWND manpath = GetDlgItem(hMainWindow, IDC_MANPATH);
  cur = LOWORD(Edit_GetSel (manpath));
  Edit_SetText (manpath, CurrentPath);
  Edit_SetSel (manpath, cur, cur);
}
/******************************************************************************/
BOOL DirectoryExists(LPCTSTR szPath)
{
  DWORD dwAttrib = GetFileAttributes(szPath);

  return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
         (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
/******************************************************************************/
void populate_dir (void)
{
  char buf[MAX_PATH];
  char mask[MAX_MASK_LEN];
  GetWindowText(GetDlgItem(hMainWindow, IDC_MANPATH), buf, sizeof(buf));
  GetWindowText(GetDlgItem(hMainWindow, IDC_MASK), mask, sizeof(mask));
  if (!DirectoryExists(buf))  {
    current_path_to_edit ();
    strcpy (buf, CurrentPath);
  }
  else  {
    size_t off;
    off = strlen(buf);
    if ((off) && (buf[off-1] != '\\') && (buf[off-1] != '/')) {
      buf[off] = '\\';
      buf[off+1] = 0;
    }
    strcpy (CurrentPath, buf);
    current_path_to_edit ();
  }
  DlgDirListComboBox(hMainWindow, buf, IDC_DRIVES, 0, DDL_DRIVES);
  DlgDirList (hMainWindow, buf, IDC_DIRS, 0, DDL_DIRECTORY + DDL_EXCLUSIVE);
  /* if you want to show only files that match mask - uncomment next line */
  //strcat (buf, mask);
  DlgDirList (hMainWindow, buf, IDC_FILES, IDC_REALPATH, 0x27);

  snprintf (mask, sizeof(mask), "[-%c-]", 'a' +_getdrive() - 1);
  ComboBox_SelectString (GetDlgItem(hMainWindow, IDC_DRIVES), 0, mask);
}

/******************************************************************************/
// main function.
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinst, LPSTR cmdline, int show)
{
  instance = hinstance;
  InitCommonControls();
  register_classes();
  h_font = CreateFont(-11, 0, 0, 0, FW_NORMAL, 0,
              0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
              DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "MS Sans Serif");


  GetModuleFileName(NULL, MyPath, sizeof(MyPath));
  //fprintf (stderr, "MyPath = %s\n", MyPath);
  if (!SHGetSpecialFolderPath(NULL, ConfigPath, CSIDL_LOCAL_APPDATA, 0))  {
    //fprintf (stderr, "Cannot determine LocalAppData folder\n");
  }
  else  {
  }
  strcat (ConfigPath, "\\.sif2\\");
  _mkdir (ConfigPath);
  //fprintf (stderr, "ConfigPath = %s\n", ConfigPath);

  config_init ();

  hMainWindow = create_wnd0();

  memset (&clfnt, 0, sizeof(clfnt));
  clfnt.lfHeight = -MulDiv(OptFontHeight, GetDeviceCaps(GetDC(hMainWindow), LOGPIXELSY), 72);
  clfnt.lfWidth = 0;
  clfnt.lfEscapement = 0;
  clfnt.lfOrientation = 0;
  clfnt.lfWeight = FW_NORMAL;
  clfnt.lfItalic = 0;
  clfnt.lfUnderline = 0;
  clfnt.lfStrikeOut = 0;
  clfnt.lfCharSet = RUSSIAN_CHARSET;
  clfnt.lfOutPrecision = OUT_DEFAULT_PRECIS;
  clfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  clfnt.lfQuality =  DEFAULT_QUALITY;
  clfnt.lfPitchAndFamily = DEFAULT_PITCH | FF_MODERN;
  strcpy (clfnt.lfFaceName, OptFontFace);

  h_font_code = CreateFontIndirect(&clfnt);

  create_wnd_content0(hMainWindow);

  _fullpath (CurrentPath, ".", sizeof(CurrentPath));
  strcat (CurrentPath, "\\");
  current_path_to_edit ();

  SetFocus(GetDlgItem(hMainWindow, IDC_TXT));
  resize_controls ();

  recent_load ();
  recent_fill_combo (IDC_RECENT);

  set_options ();
  populate_dir ();

  search_init ();

  hDlgCurrent = hMainWindow;

  if (!SHGetSpecialFolderPath(NULL, SendtoPath, CSIDL_SENDTO, 0))  {
    //fprintf (stderr, "Cannot determine SendTo folder\n");
  }
  else  {
    //fprintf (stderr, "SendtoPath = %s\n", SendtoPath);
  }

  strcat (SendtoPath, "\\Search in files.lnk");

  if (CreateShortCut(MyPath, "", SendtoPath, "Search in files", SW_SHOWNORMAL, "", "", 0) < 0)  {
    //fprintf (stderr, "Error create shortcut %ld\n", GetLastError());
  }

  do_gui_main_action (cmdline);
  return message_loop();
}

/******************************************************************************/
static void calc_ln_width (void)
{
  HDC hdc = GetDC(hLN);

  SelectObject(hdc, h_font_code);
  RECT r = {0, 0, 0, 0};

  DrawText(hdc, "88888888:", 9, &r, DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE);
  ReleaseDC(hLN, hdc);
  LNWidth = abs(r.right - r.left);
  status_bar (0, "LNW=%ld", LNWidth);
}

/******************************************************************************/
static void on_font_click (void)
{
CHOOSEFONT fnt;

  memset (&fnt, 0, sizeof(fnt));

  fnt.lStructSize = sizeof (fnt);
  fnt.hwndOwner = hMainWindow;
  //fnt.hDC = ;
  fnt.lpLogFont = &clfnt;
  fnt.iPointSize = abs(OptFontHeight) * 10;
  fnt.Flags = CF_SCREENFONTS | CF_LIMITSIZE | CF_INITTOLOGFONTSTRUCT | CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST;
  //COLORREF     rgbColors;
  //LPARAM       lCustData;
  //LPCFHOOKPROC lpfnHook;
  //LPCTSTR      lpTemplateName;
  //HINSTANCE    hInstance;
  //LPTSTR       lpszStyle;
  //WORD         nFontType;
  fnt.nSizeMin = 4;
  fnt.nSizeMax = 20;

  //clfnt.lfHeight = OptFontHeight - 1;
  status_bar (0, "%d", clfnt.lfHeight);
  status_bar (1, "%d", OptFontHeight);

  if (ChooseFont (&fnt))  {
    OptFontHeight = fnt.iPointSize/10; //clfnt.lfHeight;
    status_bar (1, "%d", OptFontHeight);
    strncpy (OptFontFace, clfnt.lfFaceName, LF_FACESIZE);
    config_save ();
    clfnt.lfHeight = -MulDiv(OptFontHeight, GetDeviceCaps(GetDC(hMainWindow), LOGPIXELSY), 72);
    status_bar (0, "%d", clfnt.lfHeight);
    DeleteObject(h_font_code);
    h_font_code = CreateFontIndirect(&clfnt);

    ListView_DeleteAllItems (hResult);
    SendMessage(hResult, WM_SETFONT, (WPARAM) h_font_code, TRUE);
    SendMessage(hRTF   , WM_SETFONT, (WPARAM) h_font_code, TRUE);
    SendMessage(hLN    , WM_SETFONT, (WPARAM) h_font_code, TRUE);
    UpdateWindow (hResult);
    UpdateWindow (hRTF);
    UpdateWindow (hLN);
    calc_ln_width();
    resize_controls();
  }
}

/******************************************************************************/
static void on_dir_dblclick (void)
{
  char buf[MAX_PATH];
  if (DlgDirSelectEx (hMainWindow, buf, sizeof(buf), IDC_DIRS))  {
    strcat (CurrentPath, buf);
    strcpy (buf, CurrentPath);
    PathCanonicalize(CurrentPath, buf);
    current_path_to_edit ();
    populate_dir ();
  }
}

/******************************************************************************/
static void on_file_dblclick (void)
{
static char filebuf[_MAX_PATH];
static char fullbuf[_MAX_PATH];
HWND fls = GetDlgItem(hMainWindow, IDC_FILES);
int index;

  index = ListBox_GetCurSel (fls);
  if (index == LB_ERR)  { // no selection
  }
  else  {
    ListBox_GetText (fls, index, filebuf);
    strcpy (fullbuf, CurrentPath);
    strcat (fullbuf, filebuf);
    show_and_highlight_file_ex (fullbuf);
  }
}

/******************************************************************************/
static void on_search_click (void)
{
char buf[256];
  //msgbox ("Seaching...");
  Edit_GetText (GetDlgItem(hMainWindow, IDC_TXT), buf, sizeof(buf));
  ListView_DeleteAllItems (hResult);
  text_set ("");
  Edit_SetText (GetDlgItem(hMainWindow, IDC_LFIND), "");
  Button_Enable (GetDlgItem (hMainWindow, IDC_SAVELF), 0);
  Button_Enable (GetDlgItem (hMainWindow, IDC_SAVECRLF), 0);

  recent_current_reset ();
  get_options ();
  if (strlen(buf) > 0)  {
    recent_add (buf);
    recent_fill_combo (IDC_RECENT);
    search_in_path (buf, CurrentPath, FileMask);
  }
  else  {
    status_bar (1, "Empty search string!");
  }
}

/******************************************************************************/
static void on_recent_select (void)
{
  HWND edit = GetDlgItem(hMainWindow, IDC_TXT);
  const char *txt = recent_get_by_list (IDC_RECENT);
  Edit_SetText (edit, txt);
  Edit_SetSel (edit, 0, -1);
  SetFocus(edit);
}

/******************************************************************************/
static void on_update_click (void)
{
  populate_dir ();
}

/******************************************************************************/
static void on_drives_select (void)
{
  char buf[_MAX_PATH];
  //HWND wnd = GetDlgItem (hMainWindow, IDC_DRIVES);
  int drive;
  if (DlgDirSelectComboBoxEx (hMainWindow, buf, sizeof(buf), IDC_DRIVES))  {
    drive = toupper(buf[0]) - 'A' + 1;
    if(_getdcwd (drive, buf, _MAX_PATH) != NULL)  {
      strcat (buf, "\\");
      PathCanonicalize(CurrentPath, buf);
      current_path_to_edit ();
      populate_dir ();
    }
  }
}

/******************************************************************************/
WNDPROC oldsearchInputProc, oldManPathProc, oldMaskProc;

LRESULT CALLBACK searchInputProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
const char *txt;

  if (msg == WM_GETDLGCODE) return DLGC_WANTALLKEYS;
  switch (msg)  {
    case WM_KEYDOWN:
      switch (wParam)  {
        case VK_RETURN:
          //Do your stuff
          on_search_click ();
          return 0;
          break;  //or return 0; if you don't want to pass it further to def proc
                  //If not your key, skip to default:
        case VK_DOWN:
          txt = recent_current_decrement ();
          Edit_SetText (wnd, txt);
          Edit_SetSel (wnd, 0, -1);
          return 0;
          break;
        case VK_UP:
          txt = recent_current_increment ();
          Edit_SetText (wnd, txt);
          Edit_SetSel (wnd, 0, -1);
          return 0;
          break;
        case VK_TAB:
          SetFocus (GetNextDlgTabItem(hMainWindow, wnd, GetAsyncKeyState(VK_SHIFT) & 0x8000 ? TRUE : FALSE));
          return 0;
        default:
          return CallWindowProc(oldsearchInputProc, wnd, msg, wParam, lParam);
      }
    default:
      //printf ("msg = 0x%X %X %X\n", msg, wParam, lParam);
      return CallWindowProc(oldsearchInputProc, wnd, msg, wParam, lParam);
   }
   return 0;
}

LRESULT CALLBACK manPathInputProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  if (msg == WM_GETDLGCODE) return DLGC_WANTALLKEYS;
  switch (msg)  {
    case WM_KEYDOWN:
      //printf ("VM_KEYDOWN %X\n", wParam);
      switch (wParam)  {
        case VK_RETURN:
          //Do your stuff
          on_update_click ();
          return 0;
          break;  //or return 0; if you don't want to pass it further to def proc
                  //If not your key, skip to default:
        case VK_TAB:
          SetFocus (GetNextDlgTabItem(hMainWindow, wnd, GetAsyncKeyState(VK_SHIFT) & 0x8000 ? TRUE : FALSE));
          return 0;

        default:
          return CallWindowProc(oldManPathProc, wnd, msg, wParam, lParam);
      }
    default:
      //printf ("msg = 0x%X %X %X\n", msg, wParam, lParam);
      return CallWindowProc(oldManPathProc, wnd, msg, wParam, lParam);
   }
   return 0;
}

LRESULT CALLBACK mask_input_proc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  if (msg == WM_GETDLGCODE) return DLGC_WANTALLKEYS;
  switch (msg)  {
    case WM_KEYDOWN:
      //printf ("VM_KEYDOWN %X\n", wParam);
      switch (wParam)  {
        case VK_RETURN:
          //Do your stuff
          get_options ();
          on_update_click ();
          return 0;
          break;  //or return 0; if you don't want to pass it further to def proc
                  //If not your key, skip to default:
        case VK_TAB:
          SetFocus (GetNextDlgTabItem(hMainWindow, wnd, GetAsyncKeyState(VK_SHIFT) & 0x8000 ? TRUE : FALSE));
          return 0;
      }
    default:
      //printf ("msg = 0x%X %X %X\n", msg, wParam, lParam);
      return CallWindowProc(oldMaskProc, wnd, msg, wParam, lParam);
   }
   return 0;
}

/******************************************************************************/
WNDPROC oldrtfProc;

LRESULT CALLBACK rtf_input_proc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch (msg)  {
    case WM_PAINT:
    //case WM_VSCROLL:
    //case WM_MOUSEWHEEL:
      fill_ln();
      //printf ("msg = scroll %X %X\n", wParam, lParam);
      return CallWindowProc(oldrtfProc, wnd, msg, wParam, lParam);
    default:
      //printf ("msg = 0x%X %X %X\n", msg, wParam, lParam);
      return CallWindowProc(oldrtfProc, wnd, msg, wParam, lParam);
   }
   return 0;
}


/******************************************************************************/
// window procedure #0 [Search in files ].
LRESULT CALLBACK wnd_proc0(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
NMLISTVIEW *ev;

    switch (msg)
    {
    case WM_COMMAND:
        switch (LOWORD(wparam))
        {
        case IDC_UPD:    // button "UPD"
            on_update_click ();
            break;

        case IDC_FONT:
            on_font_click ();
            break;

        case IDC_DIRS:
            //printf ("DIRS EVENT: %d\n", HIWORD(wparam));
            if (HIWORD(wparam) == LBN_DBLCLK) {
              on_dir_dblclick ();
            }
            break;
        case IDC_FILES:
            //printf ("FILES EVENT: %d\n", HIWORD(wparam));
            if (HIWORD(wparam) == LBN_DBLCLK) {
              on_file_dblclick ();
            }
            break;
        case IDC_SAVELF:    // button "Save LF"
            on_save_click (0);
            break;

        case IDC_SAVECRLF:    // button "Save CRLF"
            on_save_click (1);
            break;

        case IDC_RE:  // checkbox "Re"
          break;

        case IDC_CASE:  // checkbox "Case"
            break;

        case IDC_RECURSIV:    // checkbox "Recursive"
            break;

        case IDC_SEARCH:
            on_search_click ();
            break;
        case IDC_RECENT:
            if (HIWORD(wparam) == CBN_SELCHANGE) {
              on_recent_select ();
            }
            break;
        case IDC_DRIVES:
            if (HIWORD(wparam) == CBN_SELCHANGE) {
              on_drives_select ();
            }
            break;
        }
        break;

    case WM_VKEYTOITEM:
        if (lparam == (LPARAM)GetDlgItem(hMainWindow, IDC_DIRS))  {
          //printf ("VKEYTOITEM: %d %d\n", HIWORD(wparam), LOWORD(wparam));
          if ((LOWORD(wparam) == VK_RETURN) || (LOWORD(wparam) == VK_SPACE))  {
            on_dir_dblclick ();
            return -2;
          }
          else  {
            return -1;
          }
        }
        else if (lparam == (LPARAM)GetDlgItem(hMainWindow, IDC_FILES))  {
          //printf ("VKEYTOITEM: %d %d\n", HIWORD(wparam), LOWORD(wparam));
          if ((LOWORD(wparam) == VK_RETURN) || (LOWORD(wparam) == VK_SPACE))  {
            on_file_dblclick ();
            return -2;
          }
          else  {
            return -1;
          }
        }
        break;
    case WM_CREATE:
        //create_wnd_content0(hwnd);
        DragAcceptFiles(hwnd, TRUE);
        resize_controls ();
        break;

    case WM_CLOSE:
        KillTimer(hMainWindow, IDT_TMR);
        DragAcceptFiles(hwnd, FALSE);
        DestroyWindow(hwnd);
        exit(0);
        break;

    case WM_DESTROY:
        KillTimer(hMainWindow, IDT_TMR);
        PostQuitMessage(0);    // PostQuitMessage(return_code) quits the message loop.
        break;

    case WM_SIZE:
        resize_controls ();
        break;

    case WM_ACTIVATE:
        //printf ("WM_ACTIVATE: %d\n", wparam);
        if (0 == wparam) {          // becoming inactive
           hDlgCurrent = NULL;
        }
        else {                      // becoming active
          if (GetAsyncKeyState (VK_ESCAPE) & 0x8000)  {
            OnActivateEscape = 1;
          }
          hDlgCurrent = hMainWindow;
        }
        return FALSE;
    case WM_NOTIFY:
        ev = (NMLISTVIEW *)lparam;
        if ((ev->hdr.idFrom == IDC_LISTVIEW0) && (!search_is_in_progress()))  {
          //printf ("WM_NOTIFY: (code = %d %d %d %d)\n", ev->hdr.code, ev->iItem, ev->uNewState, NM_CLICK);
          if (ev->hdr.code == -2)  {
            if (ev->iItem >= 0)  {
              ////fprintf (stderr, "HDR=2: item=%d\n", ev->iItem);
              //ClickedItem = ev->iItem;
              //SetTimer(hMainWindow, IDT_TMR, 35, NULL);
            }
          }
          else if (ev->hdr.code == LVN_ITEMCHANGED)  {
            if (ev->iItem >= 0)  {
              //fprintf (stderr, "ITEM_CHANGED: item=%d\n", ev->iItem);
              ClickedItem = ev->iItem;
              SetTimer(hMainWindow, IDT_TMR, 35, NULL);
            }
          }
        }
        break;

    case WM_TIMER:
      KillTimer(hMainWindow, IDT_TMR);
      on_results_click (ClickedItem);
      fprintf (stderr, "TIMER: item=%d\n", ClickedItem);
      break;

    case WM_DROPFILES:
      fprintf (stderr, "WM_DROPFILES\n");
      do {
          //  Now comes the code that retrieves the dropped file's path...
          //  I guess this is not relevant so you don't struggle understanding it.
          //  Just know that 'buffer' will store the dropped file's path.
          HDROP hDrop = (HDROP)wparam;
          char buffer[MAX_PATH];
          char *allfiles = NULL;
          int nFilesDropped = DragQueryFile (hDrop, 0xFFFFFFFF, NULL, MAX_PATH);

          if (nFilesDropped) {
            allfiles = malloc (MAX_PATH * nFilesDropped + nFilesDropped * 2);
            if (allfiles)  {
              int i, ret;
              allfiles[0] = 0;
              for (i = 0; i < nFilesDropped; i++)  {
                ret = DragQueryFile (hDrop, i, buffer, MAX_PATH);
                if (ret)  {
                  strcat (allfiles, "\"");
                  strcat (allfiles, buffer);
                  strcat (allfiles, "\"");
                  strcat (allfiles, " ");
                }
              }
              do_gui_main_action (allfiles);
              //fprintf (stderr, "DROP: %s\n", allfiles);
              free (allfiles);
            }
          }
          DragFinish (hDrop);
      } while (0);
      break;
    default:
        return DefWindowProc(hwnd, msg, wparam, lparam);
    }
    return FALSE;
}

/******************************************************************************/
// create window #0 [Search in files ].
HWND create_wnd0()
{
    HWND wnd;
    wnd = CreateWindowEx(0x00000100, WND_CLASS_NAME0, "Search in files " VERSION_STRING, 0x14CF0000, CW_USEDEFAULT, CW_USEDEFAULT, WindowWidth, WindowHeight, NULL, NULL, instance, NULL);
    ShowWindow(wnd, SW_SHOWNORMAL);
    UpdateWindow(wnd);
    return wnd;
}

// create window content #0 [Search in files ].
void create_wnd_content0(HWND parent)
{
    HWND wnd;
    LV_COLUMN col;

    /**************************************************************************/

    wnd = CreateWindowEx(0x00000000, "Static", "", 0x50000300, 0, 28, 280, 20, parent, (HMENU) IDC_REALPATH, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    wnd = CreateWindowEx(0x00000200, "Edit", "", 0x50010080, 32, 4, 248, 18, parent, (HMENU) IDC_MANPATH, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    oldManPathProc = (WNDPROC)SetWindowLongPtr(wnd, GWLP_WNDPROC, (LONG_PTR)manPathInputProc);
    wnd = CreateWindowEx(0x00000200, "ListBox", "", 0x50010002 | WS_VSCROLL | WS_HSCROLL | LBS_HASSTRINGS | LBS_NOTIFY | LBS_WANTKEYBOARDINPUT, 0, 69, 130, 200, parent, (HMENU) IDC_DIRS, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    wnd = CreateWindowEx(0x00000000, "ComboBox", "", 0x50010303, 0, 48, 130, 121, parent, (HMENU) IDC_DRIVES, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    wnd = CreateWindowEx(0x00000200, "ListBox", "", 0x50010002 | WS_VSCROLL | WS_HSCROLL | LBS_HASSTRINGS | LBS_NOTIFY | LBS_WANTKEYBOARDINPUT, 130, 48, 150, 212, parent, (HMENU) IDC_FILES, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    wnd = CreateWindowEx(0x00000000, "Button", "&UPD", 0x50012F00, 224, 264, 44, 20, parent, (HMENU) IDC_UPD, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    wnd = CreateWindowEx(0x00000000, "Static", "Path:", 0x50000302, 0, 0, 30, 24, parent, (HMENU) IDC_STATIC2, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    wnd = CreateWindowEx(0x00000000, "Static", "File mask:", 0x50000302, 72, 264, 50, 20, parent, (HMENU) IDC_STATIC1, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    wnd = CreateWindowEx(0x00000200, "Edit", "*.*", 0x50010000, 124, 264, 94, 20, parent, (HMENU) IDC_MASK, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    Edit_LimitText (wnd, MAX_MASK_LEN-1);
    oldMaskProc = (WNDPROC)SetWindowLongPtr(wnd, GWLP_WNDPROC, (LONG_PTR)mask_input_proc);
    wnd = CreateWindowEx(0x00000000, "Button", "&Recursive", 0x50010003, 4, 264, 70, 20, parent, (HMENU) IDC_RECURSIV, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);

    /**************************************************************************/

    wnd = CreateWindowEx(0x00000000, "Button", "Save LF", 0x58012F00, 484, 264, 96, 20, parent, (HMENU) IDC_SAVELF, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    wnd = CreateWindowEx(0x00000000, "Button", "Save CRLF", 0x58012F00, 380, 264, 96, 20, parent, (HMENU) IDC_SAVECRLF, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    wnd = CreateWindowEx(0x00000000, "Edit", "", 0x50000800, 285, 264, 84, 20, parent, (HMENU) IDC_LFIND, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    wnd = CreateWindowEx(0x00000000, "Button", "Font", 0x50002F00, 684, 264, 60, 20, parent, (HMENU) IDC_FONT, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);

    wnd = CreateWindowEx(0x00000000, "ComboBox", "", 0x50010203, 588, 264, 90, 72, parent, (HMENU) IDC_SENCODING, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    SendMessage(wnd, CB_ADDSTRING, 0, (LPARAM) "Save: auto");
    SendMessage(wnd, CB_ADDSTRING, 0, (LPARAM) "Save: cp1251");
    SendMessage(wnd, CB_ADDSTRING, 0, (LPARAM) "Save: utf-8");
    ComboBox_SetCurSel (wnd, 0);

    /**************************************************************************/

    wnd = CreateWindowEx(0x00000000, "ComboBox", "", 0x50010203 | WS_VSCROLL, 176, 316, 296, 121, parent, (HMENU) IDC_RECENT, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    wnd = CreateWindowEx(0x00000000, "Button", "R&e", 0x50010003, 60, 300, 48, 14, parent, (HMENU) IDC_RE, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    Button_Enable (wnd, 0);

    wnd = CreateWindowEx(0x00000000, "Static", "Search text:", 0x50000302, 100, 296, 64, 24, parent, (HMENU) IDC_STATIC0, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    wnd = CreateWindowEx(0x00000000, "Button", "&Case", 0x50010003, 4, 300, 52, 14, parent, (HMENU) IDC_CASE, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);

    wnd = CreateWindowEx(0x00000000, "Button", "&Search", 0x50010001 | BS_DEFPUSHBUTTON, 480, 296, 80, 24, parent, (HMENU) IDC_SEARCH, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    SendMessage(wnd, BM_SETSTYLE, (WPARAM)BS_DEFPUSHBUTTON, TRUE);
    SendMessage(hMainWindow, DM_SETDEFID, (WPARAM)IDC_SEARCH, 0);

    wnd = CreateWindowEx(0x00000000, "ComboBox", "", 0x50010203, 568, 296, 110, 72, parent, (HMENU) IDC_ENCODING, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    SendMessage(wnd, CB_ADDSTRING, 0, (LPARAM) "Files: auto");
    SendMessage(wnd, CB_ADDSTRING, 0, (LPARAM) "Files: cp1251");
    SendMessage(wnd, CB_ADDSTRING, 0, (LPARAM) "Files: utf-8");
    ComboBox_SetCurSel (wnd, 0);

    wnd = CreateWindowEx(0x00000000, "Button", "Search", 0x50020007, 0, 284, 692, 60, parent, (HMENU) IDC_GROUP0, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    //wnd = CreateWindowEx(0x00000000, "ComboBox", "", 0x50010202, 164, 296, 314, 121, parent, (HMENU) IDC_TXT, instance, NULL);
    wnd = CreateWindowEx(0x00000200, "Edit", "", 0x50010000, 164, 296, 314, 21, parent, (HMENU) IDC_TXT, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    Edit_LimitText (wnd, LINE_LEN-1);
    oldsearchInputProc = (WNDPROC)SetWindowLongPtr(wnd, GWLP_WNDPROC, (LONG_PTR)searchInputProc);

    /**************************************************************************/

    wnd = CreateWindowEx(0x00000200, "SysListView32", "", 0x5001800D | LVS_SINGLESEL | LVS_NOLABELWRAP | WS_VSCROLL, 0, 328, 692, 262, parent, (HMENU) IDC_LISTVIEW0, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font_code, TRUE);
    hResult = wnd;
    col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
    col.fmt = LVCFMT_LEFT;
    col.iSubItem = 0;
    col.cx = 200;
    col.pszText = "File";
    ListView_InsertColumn (wnd, 0, &col);

    col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
    col.fmt = LVCFMT_LEFT;
    col.iSubItem = 1;
    col.cx = 500;
    col.pszText = "Text";
    ListView_InsertColumn (wnd, 1, &col);

    col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
    col.fmt = LVCFMT_LEFT;
    col.iSubItem = 2;
    col.cx = 50;
    col.pszText = "Offset";
    ListView_InsertColumn (wnd, 2, &col);

    col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
    col.fmt = LVCFMT_LEFT;
    col.iSubItem = 3;
    col.cx = 50;
    col.pszText = "File name";
    ListView_InsertColumn (wnd, 3, &col);

    ListView_SetExtendedListViewStyleEx (wnd, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
    //ListView_SetExtendedListViewStyleEx (wnd, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);

    wnd = CreateWindowEx(0x00000000, "msctls_statusbar32", "", 0x50000000, 0, 593, 692, 20, parent, (HMENU) IDC_STATUS0, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
    int nParts[2] = {550, -1};
    SendMessage(wnd,SB_SETPARTS,2,(LPARAM)&nParts);
    hStatus = wnd;

    //LoadLibrary(TEXT("riched32.dll"));
    //LoadLibrary(TEXT("riched20.dll"));
    LoadLibrary(TEXT("msftedit.dll"));

    wnd = CreateWindowEx(WS_EX_CLIENTEDGE, _T("RICHEDIT50W"), "",
        WS_VISIBLE | WS_CHILD | WS_VSCROLL | WS_HSCROLL |
        ES_MULTILINE/* | ES_NOHIDESEL*/ | ES_WANTRETURN | ES_DISABLENOSCROLL | ES_SELECTIONBAR,
        270, 0, 402, 282,
        parent, (HMENU) IDC_RTF, instance, NULL);

    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font_code, TRUE);
    hRTF = wnd;
    Edit_LimitText (wnd, -1);
    SendMessage(wnd, EM_SETMARGINS, (WPARAM)EC_LEFTMARGIN, 0);
    oldrtfProc = (WNDPROC)SetWindowLongPtr(hRTF, GWLP_WNDPROC, (LONG_PTR)rtf_input_proc);

    wnd = CreateWindowEx(0x00000200, "Edit", "", 0x50000000 | ES_RIGHT | ES_READONLY | ES_MULTILINE /* | WS_VSCROLL*/
    , 270, 0, 84, 282, parent, (HMENU) IDC_LN, instance, NULL);
    SendMessage(wnd, WM_SETFONT, (WPARAM) h_font_code, TRUE);
    hLN = wnd;
    calc_ln_width();
//    Edit_SetReadOnly (hLN, TRUE);
}

/******************************************************************************/
// register all the window classes.
void register_classes()
{
    WNDCLASS wc;

    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon         = LoadIcon(instance, IDI_APPLICATION);
    wc.hInstance     = instance;
    wc.lpszMenuName  = NULL;
    wc.style         = CS_PARENTDC | CS_DBLCLKS;

    wc.lpfnWndProc   = wnd_proc0;
    wc.lpszClassName = WND_CLASS_NAME0;

    RegisterClass(&wc);
}

/******************************************************************************/
// message loop.
int message_loop()
{
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
      SHORT k;
      k = GetAsyncKeyState (VK_ESCAPE);
      if (k & 0x8000)  {
        if (NULL != hDlgCurrent)  {  // if window is active
          //printf ("Main %p, Active %p, Foreground %p\n", hMainWindow, GetActiveWindow(), GetForegroundWindow());
          if (GetForegroundWindow() == hMainWindow)  {
            if (OnActivateEscape == 0)  {
              PostMessage(hMainWindow, WM_CLOSE, 0, 0);
            }
          }
        }
      }
      else  {
        OnActivateEscape = 0;
      }

      if (NULL == hDlgCurrent || !IsDialogMessage(hDlgCurrent, &msg)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
    }
    DeleteObject(h_font);
    DeleteObject(h_font_code);
    config_destroy ();
    search_destroy ();
    return msg.wParam;
}

/* End of file */

/******************************************************************************/
void msgbox (const char *fmt, ...)
{
va_list arg;
char buf[500];

  va_start (arg, fmt);
  vsnprintf (buf, sizeof(buf), fmt, arg);
  MessageBox (hMainWindow, buf, "Event", MB_OK|MB_ICONINFORMATION);
  va_end (arg);
}

/******************************************************************************/
void status_bar (int part, const char *fmt,...)
{
va_list arg;
static char buf[1024];

  va_start (arg, fmt);
  vsnprintf (buf, sizeof(buf), fmt, arg);
  va_end (arg);

  SendMessage(hStatus,SB_SETTEXT,part,(LPARAM)buf);
}


typedef struct dim_t  {
  double left;
  double right;
  double top;
  double bottom;
  double width;
  double height;
} dim_t;

/******************************************************************************/
static HWND get_control_size (DWORD ID, dim_t *dim)
{
HWND wnd = GetDlgItem(hMainWindow, ID);
RECT rect;
  GetWindowRect(wnd, &rect);
  MapWindowPoints (NULL, hMainWindow, (LPPOINT)&rect, 2);
  dim->left = rect.left;
  dim->right = rect.right;
  dim->top = rect.top;
  dim->bottom = rect.bottom;
  dim->width = dim->right - dim->left;
  dim->height = dim->bottom - dim->top;
  return wnd;
}

/******************************************************************************/
static void move_win (HWND wnd, dim_t *dim, int x, int y, int w, int h, BOOL redraw)
{
int xx = x, yy = y, ww = w, hh = h;
  if (x < 0)  xx = dim->left;
  if (y < 0)  yy = dim->top;
  if (w < 0)  ww = dim->width;
  if (h < 0)  hh = dim->height;
  //ClientToScreen(hMainWindow, &xx);
  MoveWindow (wnd, xx, yy, ww, hh, redraw);
}

/******************************************************************************/
static void resize_controls (void)
{
LONG wWidth, wHeight;
RECT MainWindowRect;

dim_t wh[23];

    GetWindowRect(hMainWindow, &MainWindowRect);
    wWidth  = MainWindowRect.right  - MainWindowRect.left;
    wHeight = MainWindowRect.bottom - MainWindowRect.top;

    if ((wWidth < MINIMUM_WIDTH) || (wHeight < MINIMUM_HEIGHT))  {
      if (wWidth < MINIMUM_WIDTH)  wWidth = MINIMUM_WIDTH;
      if (wHeight < MINIMUM_HEIGHT) wHeight = MINIMUM_HEIGHT;
      WindowWidth = wWidth;
      WindowHeight = wHeight;
      MoveWindow (hMainWindow, MainWindowRect.left, MainWindowRect.top, wWidth, wHeight, TRUE);
      return;
    }

    WindowWidth = wWidth;
    WindowHeight = wHeight;

    GetClientRect(hMainWindow, &MainWindowRect);
    wWidth  = MainWindowRect.right  - MainWindowRect.left;
    wHeight = MainWindowRect.bottom - MainWindowRect.top;

    HWND rtf  = get_control_size (IDC_RTF, &wh[0]);
    HWND stat = get_control_size (IDC_STATUS0, &wh[1]);
    HWND gr   = get_control_size (IDC_GROUP0, &wh[2]);
    HWND res  = get_control_size (IDC_LISTVIEW0, &wh[3]);
    HWND scrlf= get_control_size (IDC_SAVECRLF, &wh[4]);
    HWND slf  = get_control_size (IDC_SAVELF, &wh[5]);
    HWND fnt  = get_control_size (IDC_FONT, &wh[20]);
    HWND senc = get_control_size (IDC_SENCODING, &wh[21]);
    HWND ln   = get_control_size (IDC_LN, &wh[22]);

    HWND srch[6];
    srch[0] = get_control_size (IDC_CASE, &wh[6]);
    srch[1] = get_control_size (IDC_SEARCH, &wh[7]);
    srch[2] = get_control_size (IDC_ENCODING, &wh[8]);
    srch[3] = get_control_size (IDC_STATIC0, &wh[9]);
    srch[4] = get_control_size (IDC_TXT, &wh[10]);
    srch[5] = get_control_size (IDC_RE, &wh[11]);

    HWND fls[3];

    fls[0] = get_control_size (IDC_UPD, &wh[12]);
    fls[1] = get_control_size (IDC_STATIC1, &wh[13]);
    fls[2] = get_control_size (IDC_MASK, &wh[14]);
    fls[3] = get_control_size (IDC_RECURSIV, &wh[15]);

    HWND dirbox  = get_control_size (IDC_DIRS,  &wh[16]);
    HWND filebox = get_control_size (IDC_FILES, &wh[17]);

    HWND lfind = get_control_size (IDC_LFIND, &wh[18]);
    HWND recent = get_control_size (IDC_RECENT, &wh[19]);

    double button_height = wh[4].height * 1.2;

    double h = wHeight - wh[2].height - wh[1].height - button_height;
    double ih = wHeight;
    double y  = 0;

    #define HCOEFF  1.8

    move_win (ln, &wh[22], 280, 0, LNWidth, h/HCOEFF, TRUE);
    move_win (rtf, &wh[0], 280+LNWidth-2, 0, wWidth - 280 - LNWidth+2, h/HCOEFF, TRUE);
    ih -= h/HCOEFF;
    y  += h/HCOEFF;

    move_win (scrlf, &wh[4], -1, y + wh[4].height * 0.1, -1, -1, TRUE);
    move_win (slf,   &wh[5], -1, y + wh[4].height * 0.1, -1, -1, TRUE);
    move_win (lfind, &wh[18],-1, y + wh[4].height * 0.1, -1, -1, TRUE);
    move_win (fnt,   &wh[20],-1, y + wh[4].height * 0.1, -1, -1, TRUE);
    move_win (senc,  &wh[21],-1, y + wh[4].height * 0.1, -1, -1, TRUE);

    move_win (fls[0], &wh[12], -1, y + button_height/2 - wh[12].height/2, -1, -1, TRUE);
    move_win (fls[1], &wh[13], -1, y + button_height/2 - wh[13].height/2, -1, -1, TRUE);
    move_win (fls[2], &wh[14], -1, y + button_height/2 - wh[14].height/2, -1, -1, TRUE);
    move_win (fls[3], &wh[15], -1, y + button_height/2 - wh[15].height/2, -1, -1, TRUE);

    move_win (dirbox,  &wh[16], -1, -1, -1, h/HCOEFF-wh[16].top, TRUE);
    move_win (filebox, &wh[17], -1, -1, -1, h/HCOEFF-wh[17].top, TRUE);


    ih -= wh[4].height * 1.2;
    y  += wh[4].height * 1.2;

    move_win (gr, &wh[2], -1, y , wWidth, -1, TRUE);
    move_win (srch[0], &wh[6],  -1, y + wh[2].height/2.5 - wh[6].height/2, -1, -1, TRUE);
    move_win (srch[1], &wh[7],  -1, y + wh[2].height/2.5 - wh[7].height/2, -1, -1, TRUE);
    move_win (srch[2], &wh[8],  -1, y + wh[2].height/2.5 - wh[8].height/2, -1, -1, TRUE);
    move_win (srch[3], &wh[9],  -1, y + wh[2].height/2.5 - wh[9].height/2, -1, -1, TRUE);
    move_win (srch[4], &wh[10], -1, y + wh[2].height/2.5 - wh[10].height/2, -1, -1, TRUE);
    move_win (srch[5], &wh[11], -1, y + wh[2].height/2.5 - wh[11].height/2, -1, -1, TRUE);
    move_win (recent,  &wh[19], wh[10].left, wh[10].height/2 + y + wh[2].height/2.5, wh[10].width, -1, TRUE);

    y += wh[2].height;
    ih -= wh[2].height;

    move_win (res,  &wh[3], 0 , y, wWidth, ih - wh[1].height, TRUE);

    move_win (stat, &wh[1], 0, wHeight - wh[1].height, wWidth, -1, TRUE);

    ListView_SetColumnWidth (hResult, 0, (wWidth) * 30 / 100);
    ListView_SetColumnWidth (hResult, 1, (wWidth) * 70 / 100);
    ListView_SetColumnWidth (hResult, 2, (wWidth) * 5 / 100);

    UpdateWindow (rtf);
    UpdateWindow (res);
    UpdateWindow (hMainWindow);
}

/******************************************************************************/
void DoEvents (HWND hWnd)
{
MSG msg;
  while(PeekMessage(&msg, hWnd, 0, 0, PM_NOREMOVE))  {
    GetMessage(&msg, hWnd, 0, 0);
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
}

/******************************************************************************/
void do_events (void)
{
  DoEvents (hMainWindow);
}

/******************************************************************************/
void text_read_only (int ro)
{
HWND rtf = hRTF;
  Edit_SetReadOnly (rtf, ro ? TRUE : FALSE);
}

/******************************************************************************/
void fill_ln (void)
{
char buf[16];
unsigned long i;

unsigned long  line1, line2, char1, char2;
POINTL pt = {.x = 0, .y = 0};
POINTL ptn = {.x = 0, .y = 0};
RECT r;

    if (GetWindowTextLength(hRTF) < 1)  {
      SetWindowText(hLN, "");
      return;
    }

    GetClientRect(hRTF, &r);
    char1 = SendMessage(hRTF, EM_CHARFROMPOS, 0, (LPARAM)&pt);
    SendMessage(hRTF, EM_POSFROMCHAR, (LPARAM)&ptn, char1);
    //fprintf(stderr, "y=%ld\n", ptn.y);

    line1 = SendMessage(hRTF, EM_EXLINEFROMCHAR, 0, (LPARAM)char1);

    pt.y = r.bottom-1;
    char2 = SendMessage(hRTF, EM_CHARFROMPOS, 0, (LPARAM)&pt);
    line2 = SendMessage(hRTF, EM_EXLINEFROMCHAR, 0, (LPARAM)char2);

    SendMessage(hLN, WM_SETREDRAW, 0, 0);
    int eventMask = SendMessage(hLN, EM_SETEVENTMASK, 0, 0);

    SetWindowText(hLN, "");
    for (i = line1; i <= line2; i++)  {
      snprintf (buf, sizeof(buf), "%ld:\r\n", i+1);
      SendMessage(hLN, EM_SETSEL, -1, -1);
      SendMessage(hLN, EM_REPLACESEL, 0, (LPARAM)buf);
    }
    SendMessage(hLN, EM_SETSEL, -1, -1);
    SendMessage(hLN, EM_REPLACESEL, 0, (LPARAM)"\r\n\r\n");

    dim_t d;

    get_control_size (IDC_LN, &d);
    d.top = ptn.y - 2;
    d.height = d.bottom - d.top;
    move_win (hLN, &d, -1, -1, -1, -1, TRUE);

    SendMessage(hLN, EM_SETEVENTMASK, 0, eventMask);
    SendMessage(hLN, WM_SETREDRAW, 1, 0);
    //RedrawWindow(hLN, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
    UpdateWindow (hLN);
}

/******************************************************************************/
void text_set (const char *txt)
{
HWND rtf = hRTF;
  Edit_SetText (rtf, txt);
  fill_ln ();
}

/******************************************************************************/
void text_append (const char *fmt, ...)
{
va_list arg;
static char buf[8192];
HWND rtf = hRTF;
int ndx = GetWindowTextLength (rtf);

  va_start (arg, fmt);
  vsnprintf (buf, sizeof(buf), fmt, arg);
  SendMessage (rtf, EM_SETSEL, (WPARAM)ndx, (LPARAM)ndx);
  SendMessage (rtf, EM_REPLACESEL, 0, (LPARAM) ((LPSTR) buf));
  va_end (arg);
}
